package lol.clann.bukkit.pluginboot.model;

import lol.clann.bukkit.pluginboot.util.ItemStackUtils;
import lol.clann.clannboot.annotation.inject.Inject;
import lol.clann.clannboot.context.BeanContext;
import lol.clann.clannboot.util.collection.MapUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.bukkit.inventory.ItemStack;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 存储物品,自动合并
 * 不会修改传入的ItemStack引用
 *
 * @author pyz
 * @date 2018/6/17 下午4:31
 */
public class ItemStacksHolder implements Cloneable {
    /**
     * 使用类型和duriability来分组,加快添加速度
     */
    private LinkedHashMap<String, LinkedHashMap<Short, List<ItemStackHolder>>> inv = new LinkedHashMap<>();
    @Inject
    private ItemStackUtils itemUtils;

    public ItemStacksHolder() {
        BeanContext.inject(this);
    }

    public void clear() {
        inv.clear();
    }

    /**
     * 添加一个物品
     * 拷贝
     *
     * @param itemStack
     */
    public void add(ItemStack itemStack) {
        String type = itemStack.getType().name();
        short durability = itemStack.getDurability();
        LinkedHashMap<Short, List<ItemStackHolder>> byType = MapUtils.getOrCreate(inv, type, Maps::newLinkedHashMap);
        List<ItemStackHolder> list = MapUtils.getOrCreate(byType, durability, Lists::newLinkedList);
        for (ItemStackHolder stack : list) {
            if (itemUtils.isSimilar(itemStack, stack.getHandle())) {
                stack.plusQuantity(itemStack.getAmount());
                return;
            }
        }
        list.add(new ItemStackHolder(itemStack, itemStack.getAmount()));
    }

    /**
     * 移除一个物品
     * 若没有返回false
     * 若数量不足返回false
     *
     * @param itemStack
     * @return
     */
    public boolean remove(ItemStack itemStack) {
        String type = itemStack.getType().name();
        short durability = itemStack.getDurability();
        Map<Short, List<ItemStackHolder>> byType = inv.get(type);
        if (byType == null) {
            return false;
        }
        List<ItemStackHolder> list = byType.get(durability);
        if (list == null) {
            return false;
        }
        ItemStackHolder origin = null;
        Iterator<ItemStackHolder> it = list.iterator();
        while (it.hasNext()) {
            origin = it.next();
            if (!itemUtils.isSimilar(origin.getHandle(), itemStack)) {
                continue;
            }
            int count = origin.getQuantity();
            int rCount = itemStack.getAmount();
            if (count < rCount) {
                return false;
            } else if (count == rCount) {
                it.remove();
                return true;
            } else {
                origin.minusQuantity(rCount);
                return true;
            }
        }
        return false;
    }

    /**
     * 移除一个物品,若不存在,则存入,且数量设为负
     * 数量可以减为负数
     *
     * @param itemStack
     * @return
     */
    public void removeForce(ItemStack itemStack) {
        String type = itemStack.getType().name();
        short durability = itemStack.getDurability();
        Map<Short, List<ItemStackHolder>> byType = MapUtils.getOrCreate(inv, type, Maps::newLinkedHashMap);
        List<ItemStackHolder> list = MapUtils.getOrCreate(byType, durability, Lists::newLinkedList);
        for (ItemStackHolder stack : list) {
            if (itemUtils.isSimilar(itemStack, stack.getHandle())) {
                stack.minusQuantity(itemStack.getAmount());
                return;
            }
        }
        list.add(new ItemStackHolder(itemStack, -itemStack.getAmount()));
    }

    /**
     * 获取可以叠堆的物品
     *
     * @param itemStack
     * @return
     */
    @Nullable
    public ItemStackHolder getSimilar(ItemStack itemStack) {
        String type = itemStack.getType().name();
        short durability = itemStack.getDurability();
        Map<Short, List<ItemStackHolder>> byType = inv.get(type);
        if (byType == null) {
            return null;
        }
        List<ItemStackHolder> list = byType.get(durability);
        if (list == null) {
            return null;
        }
        ItemStackHolder origin = null;
        Iterator<ItemStackHolder> it = list.iterator();
        while (it.hasNext()) {
            origin = it.next();
            if (!itemUtils.isSimilar(origin.getHandle(), itemStack)) {
                continue;
            }
            return origin;
        }
        return null;
    }

    /**
     * 返回所有物品的流
     *
     * @return
     */
    @Nonnull
    public Stream<ItemStackHolder> stream() {
        return inv.values().stream().flatMap(map -> map.values().stream()).flatMap(List::stream).filter(item -> item.getQuantity() != 0);
    }

    /**
     * 返回相同type,相同durability的流
     *
     * @param itemStack
     * @return
     */
    @Nonnull
    public Stream<ItemStackHolder> stream(ItemStack itemStack) {
        return stream(itemStack.getType().name(), itemStack.getDurability()).filter(item -> item.getQuantity() != 0);
    }

    /**
     * 返回相同type的流
     *
     * @param type
     * @return
     */
    public @Nonnull
    Stream<ItemStackHolder> stream(String type) {
        Map<Short, List<ItemStackHolder>> byType = inv.get(type);
        if (byType == null) {
            return Stream.empty();
        }
        return byType.values().stream().flatMap(List::stream).filter(item -> item.getQuantity() != 0);
    }

    /**
     * 返回相同type,相同durability的流
     *
     * @param type
     * @param durability
     * @return
     */
    public @Nonnull
    Stream<ItemStackHolder> stream(String type, short durability) {
        Map<Short, List<ItemStackHolder>> byType = inv.get(type);
        if (byType == null) {
            return Stream.empty();
        }
        List<ItemStackHolder> list = byType.get(durability);
        if (list == null) {
            return Stream.empty();
        }
        return list.stream().filter(item -> item.getQuantity() != 0);
    }

}
